/*
*
给你一个整数数组 coins ，表示不同面额的硬币；以及一个整数 amount ，表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额，返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1：

输入：coins = [1, 2, 5], amount = 11
输出：3
解释：11 = 5 + 5 + 1
示例 2：

输入：coins = [2], amount = 3
输出：-1
示例 3：

输入：coins = [1], amount = 0
输出：0

提示：

1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104

  - @author ala
  - @date 2024-10-11 16:56
*/
package main

import (
	"fmt"
	"math"
)

func main() {
	//coins := []int{1, 2, 5}
	//amount := 11

	//coins := []int{2}
	//amount := 3

	coins := []int{1}
	amount := 0

	fmt.Println(coinChange(coins, amount))
}

/**
 *	1）dp[i]表示凑出i需要的最少硬币数
 *	2）dp[0] = 0
 *		dp[i] = min(dp[i - coins[j]] + 1)
 *				其中：j为面额小于i的硬币
 *	3）最终dp[amount]即为答案
 */
func coinChange(coins []int, amount int) int {
	dp := make([]int, amount+1)
	//	初始化每种金额需要无穷枚硬币
	for i := range dp {
		dp[i] = INF
	}
	dp[0] = 0
	for i := 1; i <= amount; i++ {
		for _, c := range coins {
			if i >= c {
				dp[i] = min(dp[i], dp[i-c]+1)
			}
		}
	}
	if dp[amount] == INF {
		return -1
	}
	return dp[amount]
}

var (
	INF int = math.MaxInt32 >> 1
)
